package Math::Calculus::FixedPoint;

use strict;
use warnings;

use Moose;
use Math::Calculus::Expression;

our $VERSION = '0.01';

#TODO reclamar se a exp tiver mais de uma var
has expression => ( isa => 'Str', is => 'rw', required => 1 );

#TODO reclamar se a equiv_exp tiver mais de uma var
has equiv_exp => ( isa => 'Str', is => 'rw', required => 1 );

#TODO reclamar se a variável não corresponder à da exp
has variable => ( isa => 'Str', is => 'rw', required => 1 );
has start    => ( isa => 'Num', is => 'rw', required => 1 );

#TODO receber dois valores de precisão: i. para f(x); ii. para o intervalo
has precision => ( isa => 'Num', is => 'rw', required => 1 );

#atualmente usada para ambos casos: i e ii

has partial_results => ( is => 'rw', default => sub { [] } );

sub run {
    my $self = shift;
    my ( $exp, $equiv_exp )
        = ( Math::Calculus::Expression->new,
        Math::Calculus::Expression->new );
    $exp->addVariable( my $var = $self->variable ) or die $exp->getError;
    $exp->setExpression( $self->expression )      or die $exp->getError;
    $equiv_exp->addVariable($var)                 or die $equiv_exp->getError;
    $equiv_exp->setExpression( $self->equiv_exp ) or die $equiv_exp->getError;
    my ( $x_start, $e ) = ( $self->start, 10**-$self->precision );
    my ( $x_prev, $x_next )
        = ( $x_start, $equiv_exp->evaluate( $var => $x_start ) );
    my $fx = $exp->evaluate( $var => $x_start );
    push @{ $self->partial_results }, { x => $x_start, y => $fx };
    push @{ $self->partial_results },
        { x => $x_next, y => $exp->evaluate( $var => $x_next ) };

    while ( abs $fx > $e || abs( $x_next - $x_prev ) > $e ) {
        my $aux = $x_next;
        $x_next = $equiv_exp->evaluate( x => $x_prev );
        $fx     = $exp->evaluate( x       => $x_next );
        push @{ $self->partial_results }, { x => $x_next, y => $fx };
        $x_prev = $aux;
    }
    return $x_next;
}

1;
__END__


=head1 NAME

Math::Calculus::FixedPoint -

=head1 SYNOPSIS

  use Math::Calculus::FixedPoint;

=head1 DESCRIPTION



=head2 EXPORT

None by default.

=head1 SEE ALSO

Math::Calculus::Expression, Math::Calculus::NewtonRaphson

=head1 AUTHORS

Wallace Reis E<lt>wreis@cpan.orgE<gt>, Eden Cardim E<lt>edenc@cpan.orgE<gt>

=head1 COPYRIGHT AND LICENSE

Copyright (C) 2007 by Wallace Reis

This library is free software; you can redistribute it and/or modify
it under the same terms as Perl itself, either Perl version 5.8.8 or,
at your option, any later version of Perl 5 you may have available.


=cut
